/**
 * Company : Thai Informatic System Co., Ltd.
 * Created By : Chatree Siangklom
 * Created On : Feb 4, 2013  1:29:05 PM 
 * e-Mail : dr_chatree@hotmail.com
 * Mobile Phone : (+66) 087-921-5115
 * Package Name : com.tis.std
 * File Name : QueueServerThreadPool.java
 * TODO
 */
package com.tis.std;

import java.beans.Statement;
import java.sql.Connection;
import java.util.Date;
import java.util.LinkedList;

import jpa.entitys.synchro.staging.SyncQueue;

import org.apache.log4j.Logger;

import com.tis.QueueCommon;

import promis.db.connection.dbHelper;
import apps.promis.out.common.SyncQueueAction;

/**
 * 
 * @author Chatree Siangklom of Administrator
 * Date =Nov 19, 2013 : 9:51:33 AM 
 * CreateBy=Chatree Siangklom
 * 
 * QueueServerThreadPool
 * TODO
 */
public class QueueServerThreadPool extends QueueCommon {
	
	private static final Logger log = Logger.getLogger(QueueServerThreadPool.class);
	private static final long MEGABYTE = 1024L * 1024L;

	public static long bytesToMegabytes(long bytes) {		  		  
		  return (bytes / MEGABYTE);
	}
	
	/*
	public static void getQueue()throws Exception {
		try{
			dbHelper dbHelp = new dbHelper();
			Connection conn = dbHelp.getConn();
			try {
				
				int numTasks = 1;	    
				int numThreads = 2;
				if(conn != null)
				{
					System.out.println("numTasks = " + numTasks + " //numThreads = " + numThreads + "//Connect status:" + (conn.isClosed() ? "Closed" : "Open"));
				}
				else{
					System.out.println("numTasks = " + numTasks + " //numThreads = " + numThreads + "//Connect status: null");	
				}
				
				// create the thread pool
				 ThreadPool threadPool = new ThreadPool(numThreads);				 
				 while(true)
				 {
					 SyncQueueAction queueAction = new SyncQueueAction();
					 SyncQueue queue = queueAction.GetQueue();
					 if(queue != null){
						 
						 if(conn == null)
							 conn = dbHelp.getConn();
						 
						 if(conn.isClosed())
							 conn = dbHelp.getConn();
						 
						 if(CommonService.IsNullRString(queue.getProcessModule()).equals("COMMONS")){
							 threadPool.runTask(createTask(queue.getQueueId().toString(), conn, queue));
							 //threadPool.join();
						 }else
						 {
							 QueueProcessing qServ = new QueueProcessing();
							 qServ.ProcRun(queue, conn);
							 qServ = null;
						 }
					 }					 					
					 
					 // Get the Java runtime
					 Runtime runtime = Runtime.getRuntime();
					 
				    // Calculate the used memory		    
					long memory = runtime.totalMemory() - runtime.freeMemory();
					System.out.println("totalMemory: " + bytesToMegabytes(runtime.totalMemory()) + "MB." 
		    							+ " //freeMemory: " + bytesToMegabytes(runtime.freeMemory()) + "MB." 
		    							+ " //Used memory is bytes: " +  memory
		    							+ " //Used memory is megabytes: " + bytesToMegabytes(memory)  + "MB.");					
					    
				    // Run the garbage collector
				    runtime.gc();
				    //System.gc();
				    Thread.sleep(1000);
				    //queue = null;
				    queueAction = null;
				 }
				 
			} catch (Exception e) {				
				
				e.printStackTrace();
				log.error(e.getMessage());
				System.out.println(e.getMessage());
			}
		}catch(Exception e){
			e.printStackTrace();
			log.error(e.getMessage());
			System.out.println(e.getMessage());
			getQueue();
		}
	}
	
	*/
	
	/**
	 * Date =Nov 26, 2013 : 3:17:04 PM 
	 * CreateBy=Chatree Siangklom
	 * void
	 * TODO
	 * @throws Exception
	 */
	public static void getQueue()throws Exception {
		try{
			dbHelper dbHelp = new dbHelper();
			Connection conn = dbHelp.getConn();
			try {
				int numTasks = 1;	    
				int numThreads = 1;
				System.out.println("numTasks = " + numTasks + " //numThreads = " + numThreads);
				// create the thread pool
				 ThreadPool threadPool = new ThreadPool(numThreads);
				 
				 while(true)
				 {
					 SyncQueueAction queueAction = new SyncQueueAction();
					 SyncQueue queue = queueAction.GetQueue();					 					
					 if(queue != null){
						 if(conn == null)
							 conn = dbHelp.getConn();
						 
						 if(conn.isClosed())
							 conn = dbHelp.getConn();
						 
						 threadPool.runTask(createTask(queue.getQueueId().toString(), conn, queue));
					 }					 					
					 
					 // Get the Java runtime
					 Runtime runtime = Runtime.getRuntime();
					 
				    // Calculate the used memory		    
					long memory = runtime.totalMemory() - runtime.freeMemory();
					System.out.println("totalMemory: " + bytesToMegabytes(runtime.totalMemory()) + "MB."  + " //freeMemory: " + bytesToMegabytes(runtime.freeMemory()) + "MB."  + " //Used memory is bytes: " +  memory + " //Used memory is megabytes: " + bytesToMegabytes(memory)  + "MB.");
					    
				    // Run the garbage collector
				    runtime.gc();
				    //System.gc();
				    Thread.sleep(600);
				    //queue = null;
				    queueAction = null;
				 }
			} catch (Exception e) {
				e.printStackTrace();
				log.error(e.getMessage());
				System.out.println(e.getMessage());
			}
		}catch(Exception e){
			e.printStackTrace();
			log.error(e.getMessage());
			System.out.println(e.getMessage());
			getQueue();
		}
	}
	
	public static void main(String[] args) {
		try{
			
			getQueue();
			
		}catch(Exception e){
			e.printStackTrace();
			log.error(e.getMessage());
			System.out.println(e.getMessage());
		}
	}
	
	/**
	   * Creates a simple Runnable that prints an ID, waits 500 milliseconds, then
	   * prints the ID again.
	   */
	  private static Runnable createTask(final String queueId, final Connection conn, final SyncQueue queue) {
	    return new Runnable() {
	      public void run() {
	       try{
	    	   System.err.println(Thread.currentThread().getName() + " :: START :: " + (new Date()) + " :: Task QueueId=" + queueId);

		        // simulate a long-running task
		        ////////////////////////////////////////////////////////////////////////////////////////
		        QueueProcessing qServ = new QueueProcessing();
	            try {
	            	        	
	    			qServ.ProcRun(queue, conn);
	    			 
	                Thread.sleep(600);
	            } catch (InterruptedException e) {
	                e.printStackTrace();
	            } catch (Exception e) {
	    			e.printStackTrace();
	    		}finally{
	    			qServ = null;
	    		}
		        //////////////////////////////////////////////////////////////////////////////////////		        
	       }finally
	       {
	    	   System.err.println(Thread.currentThread().getName() + " :: END :: " + (new Date()) + " :: Task QueueId=" + queueId);
	       }
	      }
	    };
	  }
}

class ThreadPool extends ThreadGroup {

	  private boolean isAlive;
	  private LinkedList taskQueue;
	  private int threadID;
	  private static int threadPoolID;

	  /**
	   * Creates a new ThreadPool.
	   * 
	   * @param numThreads
	   *            The number of threads in the pool.
	   */
	  public ThreadPool(int numThreads) {
	    super("ThreadPool-" + (threadPoolID++));
	    setDaemon(true);

	    isAlive = true;
	    taskQueue = new LinkedList();
	    for (int i = 0; i < numThreads; i++) {
	      new PooledThread().start();
	    }
	  }

	  /**
	   * Requests a new task to run. This method returns immediately, and the task
	   * executes on the next available idle thread in this ThreadPool.
	   * <p>
	   * Tasks start execution in the order they are received.
	   * 
	   * @param task
	   *            The task to run. If null, no action is taken.
	   * @throws IllegalStateException
	   *             if this ThreadPool is already closed.
	   */
	  public synchronized void runTask(Runnable task) {
	    if (!isAlive) {
	      throw new IllegalStateException();
	    }
	    if (task != null) {
	      taskQueue.add(task);
	      notify();
	    }

	  }

	  protected synchronized Runnable getTask() throws InterruptedException {
	    while (taskQueue.size() == 0) {
	      if (!isAlive) {
	        return null;
	      }
	      wait();
	    }
	    return (Runnable) taskQueue.removeFirst();
	  }

	  /**
	   * Closes this ThreadPool and returns immediately. All threads are stopped,
	   * and any waiting tasks are not executed. Once a ThreadPool is closed, no
	   * more tasks can be run on this ThreadPool.
	   */
	  public synchronized void close() {
	    if (isAlive) {
	      isAlive = false;
	      taskQueue.clear();
	      interrupt();
	    }
	  }

	  /**
	   * Closes this ThreadPool and waits for all running threads to finish. Any
	   * waiting tasks are executed.
	   */
	  public void join() {
	    // notify all waiting threads that this ThreadPool is no
	    // longer alive
	    synchronized (this) {
	      isAlive = false;
	      notifyAll();
	    }

	    // wait for all threads to finish
	    Thread[] threads = new Thread[activeCount()];
	    int count = enumerate(threads);
	    for (int i = 0; i < count; i++) {
	      try {
	        threads[i].join();
	      } catch (InterruptedException ex) {
	      }
	    }
	  }

	  /**
	   * A PooledThread is a Thread in a ThreadPool group, designed to run tasks
	   * (Runnables).
	   */
	  private class PooledThread extends Thread {

	    public PooledThread() {
	      super(ThreadPool.this, "PooledThread-" + (threadID++));
	    }

	    public void run() {
	      while (!isInterrupted()) {

	        // get a task to run
	        Runnable task = null;
	        try {
	          task = getTask();
	        } catch (InterruptedException ex) {
	        }

	        // if getTask() returned null or was interrupted,
	        // close this thread by returning.
	        if (task == null) {
	          return;
	        }

	        // run the task, and eat any exceptions it throws
	        try {
	          task.run();
	        } catch (Throwable t) {
	          uncaughtException(this, t);
	        }
	      }
	    }
	  }
}

